package com.eostoken.eos_wallet.utils;


import android.app.Activity;
import android.content.Context;

import com.blankj.utilcode.util.GsonUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ObjectUtils;
import com.blankj.utilcode.util.SPUtils;
import com.blankj.utilcode.util.StringUtils;
import com.eostoken.eos_wallet.R;
import com.eostoken.eos_wallet.bean.AccountNames;
import com.eostoken.eos_wallet.db.MgpWallet;
import com.eostoken.eos_wallet.db.greendao.DBManager;
import com.eostoken.eos_wallet.db.greendao.MgpWalletDao;
import com.eostoken.eos_wallet.eosnet.common.EOSNetWorkManager;
import com.eostoken.eos_wallet.eosnet.common.Params;
import com.eostoken.eos_wallet.mvp.callback.CommonCallback;
import com.eostoken.eos_wallet.net.common.RxSubscriber;

import org.greenrobot.greendao.query.QueryBuilder;

import java.util.List;
import java.util.Map;

import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import party.loveit.eosforandroidlibrary.Ecc;

import static com.eostoken.eos_wallet.utils.Constants.ADD_WALLET_FAIL;
import static com.eostoken.eos_wallet.utils.Constants.ADD_WALLET_SUCCEED;
import static com.eostoken.eos_wallet.utils.Constants.IMPORT_WALLET_MNEMONIC;
import static com.eostoken.eos_wallet.utils.Constants.IMPORT_WALLET_PRIVATEKEY;
import static com.eostoken.eos_wallet.utils.Constants.INVALID;
import static com.eostoken.eos_wallet.utils.Constants.VALID;

public class WalletUtils {

    /**
     * 根据私钥（privatekey）查询钱包实体类（MgpWallet）
     */
    public static void queryWallet(Context context, final String accountName, CommonCallback listener) {
        Observable.fromCallable(() -> DBManager.getInstance(context).getDaoSession().getMgpWalletDao().queryBuilder()
                .where(MgpWalletDao.Properties.CurrentAccountName.eq(accountName))
                .orderAsc(MgpWalletDao.Properties.CurrentAccountName))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(new Observer<QueryBuilder<MgpWallet>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        LogUtils.dTag("queryBuilder==", "onSubscribe = " + d.toString());
                    }

                    @Override
                    public void onNext(QueryBuilder<MgpWallet> mgpWalletQueryBuilder) {
                        List<MgpWallet> walletList = mgpWalletQueryBuilder.build().list();
                        if (ObjectUtils.isEmpty(walletList)) {
                            listener.onFailure(StringUtils.getString(R.string.str_wallet_inexistence), Constants.WALLET_INEXISTENCE);
                        } else {
                            if (walletList.size() <= 0) {
                                listener.onFailure(StringUtils.getString(R.string.str_wallet_inexistence), Constants.WALLET_INEXISTENCE);
                            } else {
                                listener.onSuccess(walletList, StringUtils.getString(R.string.str_wallet_exist), Constants.WALLET_EXIST);
                            }
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        listener.onFailure(e.toString(), Constants.SQL_FAIL);
                        LogUtils.dTag("queryBuilder==", "onError = " + e.toString());
                    }

                    @Override
                    public void onComplete() {
                        LogUtils.dTag("queryBuilder==", "onComplete = ");
                    }
                });
    }

    /**
     * 获取所有钱包实体类（MgpWallet）
     */
    public static void getAllWalletList(Context context, CommonCallback listener) {
        Observable.fromCallable(() -> DBManager.getInstance(context).getDaoSession().getMgpWalletDao().queryBuilder())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(new Observer<QueryBuilder<MgpWallet>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        LogUtils.dTag("queryBuilder==", "onSubscribe = " + d.toString());
                    }

                    @Override
                    public void onNext(QueryBuilder<MgpWallet> mgpWalletQueryBuilder) {
                        List<MgpWallet> walletList = mgpWalletQueryBuilder.build().list();
                        if (ObjectUtils.isEmpty(walletList)) {
                            listener.onFailure(StringUtils.getString(R.string.str_wallet_inexistence), Constants.WALLET_INEXISTENCE);
                        } else {
                            if (walletList.size() <= 0) {
                                listener.onFailure(StringUtils.getString(R.string.str_wallet_inexistence), Constants.WALLET_INEXISTENCE);
                            } else {
                                listener.onSuccess(walletList, StringUtils.getString(R.string.str_wallet_exist), Constants.WALLET_EXIST);
                            }
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        listener.onFailure(e.toString(), Constants.SQL_FAIL);
                        LogUtils.dTag("queryBuilder==", "onError = " + e.toString());
                    }

                    @Override
                    public void onComplete() {
                        LogUtils.dTag("queryBuilder==", "onComplete = ");
                    }
                });
    }

    public static void updateWallet(Context context, MgpWallet wallet) {
        DBManager.getInstance(context).getDaoSession().getMgpWalletDao().updateInTx(wallet);
    }

    public static void importWallet(Activity context, final String privatekey, CommonCallback listener) {
        String publicKey = Ecc.privateToPublic(privatekey);
        getKeyAccounts(context, publicKey, listener);
    }

    public static void getKeyAccounts(Activity context, String publicKey, CommonCallback listener) {
        Map<String, Object> map = Params.getKeyAccountsPamars(publicKey);
        Observable.fromCallable(() -> EOSNetWorkManager.getRpcProvider().getKeyAccounts(Params.getRequestBody(map)))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(new RxSubscriber<String>(context, true) {

                    @Override
                    public void onFail(String failMsg) {
                        listener.onFailure(StringUtils.getString(R.string.str_import_wallet_fail), ADD_WALLET_FAIL);
                    }

                    @Override
                    public void onSuccess(String s) {
                        if (ObjectUtils.isEmpty(s)) {
                            listener.onFailure(StringUtils.getString(R.string.str_import_wallet_fail), ADD_WALLET_FAIL);
                            return;
                        }
                        AccountNames accountNames = GsonUtils.fromJson(s, AccountNames.class);
                        if (ObjectUtils.isEmpty(accountNames)) {
                            listener.onFailure(StringUtils.getString(R.string.str_import_wallet_fail), ADD_WALLET_FAIL);
                            return;
                        }
                        List<String> accountList = accountNames.getAccount_names();
                        if (accountList != null) {
                            if (accountList.size() <= 0) {
                                listener.onFailure(StringUtils.getString(R.string.str_import_wallet_fail), ADD_WALLET_FAIL);
                            } else {
//                                String currentAccountName = accountList.get(0);
//                                MgpWallet mgpWallet = addWallet(context, accountList, currentAccountName, password, privatekey, publicKey, mnemonicList, hint);
                                listener.onSuccess(accountNames, StringUtils.getString(R.string.str_add_wallet_success), ADD_WALLET_SUCCEED);
                            }
                        }
                    }
                });
    }

    public static MgpWallet addWallet(Context context, String currentAccountName, String password, String privatekey, String publicKey, List<String> mnemonicList, String hint) {
        MgpWallet mgpWallet;
        List<MgpWallet> walletList = DBManager.getInstance(context).getDaoSession().getMgpWalletDao().queryBuilder()
                .where(MgpWalletDao.Properties.CurrentAccountName.eq(currentAccountName))
                .orderAsc(MgpWalletDao.Properties.CurrentAccountName).build().list();
        if (ObjectUtils.isNotEmpty(walletList)) {
            if (walletList.size() > 0) {
                mgpWallet = walletList.get(0);
                return mgpWallet;
            }
        }
        mgpWallet = new MgpWallet();
        mgpWallet.setAccountNameList(null);
        mgpWallet.setCurrentAccountName(currentAccountName);
        mgpWallet.setWalletPassword(password);
        mgpWallet.setPrivateKey(privatekey);
        mgpWallet.setPublicKey(publicKey);
        mgpWallet.setLocked(false);
        mgpWallet.setMnemonicCode(mnemonicList);
        mgpWallet.setHint(hint);
        mgpWallet.setWalletName(StringUtils.getString(R.string.str_mgp_wallet_1));
        DBManager.getInstance(context).getDaoSession().getMgpWalletDao().insert(mgpWallet);
        SPUtils.getInstance(Constants.SP_WALLET).put(Constants.KEY_CURRENT_ACCOUNT_NAME, currentAccountName);
        SPUtils.getInstance(Constants.SP_WALLET).put(Constants.KEY_CURRENT_WALLET_PRIVATEKEY, privatekey);
        return mgpWallet;
    }

    public static String getCurrentAccountName() {
        return SPUtils.getInstance(Constants.SP_WALLET).getString(Constants.KEY_CURRENT_ACCOUNT_NAME, "");
    }

    public static String getCurrentPrivatekey() {
        return SPUtils.getInstance(Constants.SP_WALLET).getString(Constants.KEY_CURRENT_WALLET_PRIVATEKEY, "");
    }

    public static void setCurrentAccountName(String accountname) {
        SPUtils.getInstance(Constants.SP_WALLET).put(Constants.KEY_CURRENT_ACCOUNT_NAME, accountname);
    }

    public static void setCurrentPrivatekey(String privatekey) {
        SPUtils.getInstance(Constants.SP_WALLET).put(Constants.KEY_CURRENT_WALLET_PRIVATEKEY, privatekey);
    }

    public static MgpWallet getCurrentWallet(Context context) {
        List<MgpWallet> mgpWallets = DBManager.getInstance(context).getDaoSession().getMgpWalletDao().queryBuilder()
                .where(MgpWalletDao.Properties.CurrentAccountName.eq(getCurrentAccountName()))
                .orderAsc(MgpWalletDao.Properties.CurrentAccountName).build().list();
        MgpWallet wallet = null;
        if (mgpWallets != null) {
            if (mgpWallets.size() > 0) {
                wallet = mgpWallets.get(0);
            } else {
                wallet = new MgpWallet();
            }
        } else {
            wallet = new MgpWallet();
        }
        return wallet;
    }

    public static void deleteWallet(Context context, MgpWallet wallet) {
        WalletUtils.setCurrentAccountName("");
        WalletUtils.setCurrentPrivatekey("");
        DBManager.getInstance(context).getDaoSession().getMgpWalletDao().delete(wallet);
    }


    public static void getVerifyWallet(Context context, String account, CommonCallback listener) {
        Map<String, Object> map = Params.getAccountPamars(account);
        Observable.fromCallable(() -> EOSNetWorkManager.getRpcProvider().getAccount(Params.getRequestBody(map)))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(String s) {
                        listener.onSuccess(s, null, VALID);
                    }

                    @Override
                    public void onError(Throwable e) {
                        listener.onFailure(e.toString(), INVALID);
                    }

                    @Override
                    public void onComplete() {

                    }
                });

    }

}
